package Main;
import com.cloudgarden.resource.SWTResourceManager;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.Map.Entry;
import javax.swing.JOptionPane;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.MouseTrackAdapter;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

/**
* This code was edited or generated using CloudGarden's Jigloo
* SWT/Swing GUI Builder, which is free for non-commercial
* use. If Jigloo is being used commercially (ie, by a corporation,
* company or business for any purpose whatever) then you
* should purchase a license for each developer using Jigloo.
* Please visit www.cloudgarden.com for details.
* Use of Jigloo implies acceptance of these licensing terms.
* A COMMERCIAL LICENSE HAS NOT BEEN PURCHASED FOR
* THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED
* LEGALLY FOR ANY CORPORATE OR COMMERCIAL PURPOSE.
*/
public class Main {
	private String divider="/"; //!!!divider in path
	private Document doc=null; // the loaded XML document
	private Element curRoot=null; //represents the element in current path
	private String xmlFile="";
	private String dtd="";
	private String prevPath="";
	private String errors="";
	private int scrollIndex=0; // represents the index of the current scrolling range
	private int selectionIndex=-1; // represents the index of the currently selected node in the list
	private boolean nodeSelected = false; // true if any node in the current node list is selected
	//==========GUI stuff===========
	private Shell sShell = null;
	private Label label1;
	private Button button6;
	private Label label7;
	private TreeMap<String,String> currNodes = new TreeMap<String,String>();
	private Button button7;
	private Button button5;
	private Button[] buttons = new Button[5];
	private List list2;
	private List list1;
	private Button button4;
	private Button button3;
	private Text text3;
	private Label label6;
	private Button button2;
	private Label label5;
	private Label label4;
	private Label label3;
	private Text text2;
	private Text text1;
	private Label label2;
	private Button button1;
	private SelectionListener itemListener;
	private Label label9;
	private Label label8;
	private Label label10;
	private Label label11;
	private List list4;
	private List list3; 
	private ScrollBar scroll1;
	private ScrollBar scroll2;
	private ScrollBar scroll3;
	private ScrollBar scroll4;
	//private Image bg;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		/* Before this is run, be sure to set up the launch configuration (Arguments->VM Arguments)
		 * for the correct SWT library path in order to run with the SWT dlls. 
		 * The dlls are located in the SWT plugin jar.  
		 * For example, on Windows the Eclipse SWT 3.1 plugin jar is:
		 *       installation_directory\plugins\org.eclipse.swt.win32_3.1.0.jar
		 */
		Display display = Display.getDefault();
		Main thisClass = new Main();
		thisClass.createSShell();
		thisClass.sShell.open();

		while (!thisClass.sShell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
		display.dispose();
	}

	/**
	 * This method initializes sShell
	 */
	private void createSShell() {
		File f = new File("");
		String go=new String(f.getAbsolutePath());
		Image bg=new Image(Display.getDefault(),go+"/image.jpg");
		sShell = new Shell(Display.getDefault(),SWT.CLOSE|SWT.MIN);

		{
			//Register as a resource user - SWTResourceManager will
			//handle the obtaining and disposing of resources
			SWTResourceManager.registerResourceUser(sShell);
		}
		
		sShell.setText("XML Browser");
		sShell.setBackgroundImage(bg);		
		sShell.setSize(542, 513);
		sShell.setLayout(null);

		{
			button1 = new Button(sShell, SWT.PUSH | SWT.CENTER);
			button1.setText("Open XML");
			button1.setBounds(17, 25, 76, 29);
			button1.setBackgroundImage(bg);
			button1.addSelectionListener(new SelectionAdapter() {
				public void widgetSelected(SelectionEvent evt) {
					try {
						button1WidgetSelected(evt);
					}				
					      catch ( SAXParseException spe ) {
					          label7.setText("XML Parse Failed");
					       }

					       catch ( SAXException se ) {
					    	   System.out.println("SAX exception");
					          se.printStackTrace();         
					       }

					       catch ( FileNotFoundException fne ) {
					    	   label7.setText("DTD file not found");
					       }
					       catch (Exception e) {
								if(!errors.equals(""))
								{
									button6.setVisible(true);
								}	

								else {
								// TODO Auto-generated catch block
									label7.setText("XML Parse Failed");
									//e.printStackTrace();
								 }
							}
					    }
			});
		}
		{
			label1 = new Label(sShell, SWT.RIGHT);
			label1.setText("Current Path:");
			label1.setBounds(152, 28, 101, 21);
			label1.setBackgroundImage(bg);
			label1.setForeground(SWTResourceManager.getColor(255,255,255));
		}
		{
			label2 = new Label(sShell, SWT.RIGHT | SWT.WRAP);
			label2.setText("Relative Expression:");
			label2.setBounds(147, 68, 106, 21);
			label2.setBackgroundImage(bg);
			label2.setForeground(SWTResourceManager.getColor(255,255,255));
		}
		{
			text1 = new Text(sShell, SWT.BORDER);
			text1.setBounds(258, 28, 222, 21);
			text1.setEnabled(false);
			text1.addMouseTrackListener(new MouseTrackAdapter() {
				public void mouseExit(MouseEvent evt) {
					label11.setText("");
				}
				public void mouseEnter(MouseEvent evt) {
					label11.setText(text1.getText());
				}
			});
			text1.addFocusListener(new FocusAdapter() {
				public void focusGained(FocusEvent evt) {
					text1FocusGained(evt);
				}});
			
			text1.addFocusListener(new FocusAdapter() {
				public void focusLost(FocusEvent evt) {
					text1FocusLost(evt);
				}});
		}
		{
			text2 = new Text(sShell, SWT.BORDER);
			text2.setBounds(259, 68, 222, 21);
			text2.setEditable(false);
			text2.setEnabled(false);
			text2.addMouseTrackListener(new MouseTrackAdapter() {
				public void mouseExit(MouseEvent evt) {
					label11.setText("");
				}
				public void mouseEnter(MouseEvent evt) {
					label11.setText(text2.getText());
				}
			});
		}
		{
			label3 = new Label(sShell, SWT.CENTER | SWT.WRAP);
			label3.setText("Current Node List:");
			label3.setBounds(61, 98, 101, 21);
			label3.setBackgroundImage(bg);
			label3.setForeground(SWTResourceManager.getColor(255,255,255));
		}
		{
			label4 = new Label(sShell, SWT.LEFT | SWT.WRAP);
			label4.setText("Elements:");
			label4.setBounds(10, 188, 92, 21);
			label4.setBackgroundImage(bg);
			label4.setForeground(SWTResourceManager.getColor(255,255,255));
		}
		{
			label5 = new Label(sShell, SWT.LEFT | SWT.WRAP);
			label5.setText("Values:");
			label5.setBounds(111, 188, 101, 21);
			label5.setBackgroundImage(bg);
			label5.setForeground(SWTResourceManager.getColor(255,255,255));
		}
		{
			button2 = new Button(sShell, SWT.PUSH | SWT.CENTER);
			button2.setText("Back");
			button2.setBackgroundImage(bg);
			button2.setEnabled(false);
			button2.setBounds(200, 425, 91, 30);
			button2.addSelectionListener(new SelectionAdapter() {
				public void widgetSelected(SelectionEvent evt) {
					try {
						button2WidgetSelected(evt);
					} catch (Exception e) {e.printStackTrace();}					
				}
			});
		}
		{
			label6 = new Label(sShell, SWT.RIGHT | SWT.WRAP);
			label6.setText("Name/Value:");
			label6.setBounds(152, 156, 101, 21);
			label6.setBackgroundImage(bg);
			label6.setForeground(SWTResourceManager.getColor(255,255,255));
		}
		{
			text3 = new Text(sShell, SWT.BORDER);
			text3.setBounds(258, 156, 222, 21);
			text3.setEnabled(false);
			text3.setEditable(false);
			text3.addMouseTrackListener(new MouseTrackAdapter() {
				public void mouseExit(MouseEvent evt) {
					label11.setText("");
				}
				public void mouseEnter(MouseEvent evt) {
					label11.setText(text3.getText());
				}
			});

		}
		{
			button3 = new Button(sShell, SWT.PUSH | SWT.CENTER);
			button3.setText("<");
			button3.setBackgroundImage(bg);
			button3.setBounds(13, 119, 37, 28);
			button3.setEnabled(false);
			button3.addSelectionListener(new SelectionAdapter() {
				public void widgetSelected(SelectionEvent evt) {
					try {
						button3WidgetSelected(evt);
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			});
		}
		{
			button4 = new Button(sShell, SWT.PUSH | SWT.CENTER);
			button4.setText(">");
			button4.setBackgroundImage(bg);
			button4.setBounds(475, 119, 39, 28);
			button4.setEnabled(false);
			button4.addSelectionListener(new SelectionAdapter() {
				public void widgetSelected(SelectionEvent evt) {
					try {
						button4WidgetSelected(evt);
					} catch (Exception e) {e.printStackTrace();}
				}
			});
		}
		{
			list1 = new List(sShell, SWT.V_SCROLL | SWT.BORDER);
			list1.setBounds(10, 216, 92, 207);
			list1.setEnabled(false);
			scroll1=list1.getVerticalBar();
			scroll1.addListener (SWT.Selection, new Listener () {
				public void handleEvent (Event event) {
					scroll2.setSelection(scroll1.getSelection());
					list2.setTopIndex(list1.getTopIndex());
				}
			});
			list1.addMouseTrackListener(new MouseTrackAdapter() {
				public void mouseExit(MouseEvent evt) {
					label11.setText("");
				}
			});
			list1.addMouseMoveListener(new MouseMoveListener() {
				public void mouseMove(MouseEvent evt) {
					//System.out.println(evt);
					int element;
					//compute at which element of the list mouse cursor is
					element=scroll1.getSelection()+evt.y/list1.getItemHeight();
					if(element>=list1.getItemCount()){
						label11.setText("");
					}
					else{
						label11.setText(list1.getItem(element));
					}
				}
			});
		}
		{
			list2 = new List(sShell, SWT.V_SCROLL | SWT.BORDER);
			list2.setBounds(110, 216, 144, 207);
			list2.setSelection(new java.lang.String[] {""});
			list2.setEnabled(false);
			scroll2=list2.getVerticalBar();
			scroll2.addListener (SWT.Selection, new Listener () {
				public void handleEvent (Event event) {
					scroll1.setSelection(scroll2.getSelection());
					list1.setTopIndex(list2.getTopIndex());
				}
			});
			list2.addMouseTrackListener(new MouseTrackAdapter() {
				public void mouseExit(MouseEvent evt) {
					label11.setText("");
				}
			});
			list2.addMouseMoveListener(new MouseMoveListener() {
				public void mouseMove(MouseEvent evt) {
					int element;
					//compute at which element of the list mouse cursor is
					element=scroll2.getSelection()+evt.y/list2.getItemHeight();
					if(element>=list2.getItemCount()){
						label11.setText("");
					}
					else{
						label11.setText(list2.getItem(element));
					}
				}
			});
		}		
		{
			button5 = new Button(sShell, SWT.PUSH | SWT.CENTER);
			button5.setText("Forward");
			button5.setBackgroundImage(bg);
			button5.setBounds(291, 425, 91, 30);
			button5.setEnabled(false);
			button5.addSelectionListener(new SelectionAdapter() {
				public void widgetSelected(SelectionEvent evt) {
					try {
						button5WidgetSelected(evt);
					} catch (Exception e) {e.printStackTrace();}
				}
			});
		}
		{
			buttons[0] = new Button(sShell, SWT.TOGGLE | SWT.CENTER);
			buttons[0].setBounds(68, 125, 78, 22);
			buttons[0].setBackgroundImage(bg);
			buttons[0].addMouseTrackListener(new MouseTrackAdapter() {
				public void mouseExit(MouseEvent evt) {
					label11.setText("");
				}
				public void mouseEnter(MouseEvent evt) {
					label11.setText(buttons[0].getToolTipText());
				}
			});
		}
		{
			buttons[1] = new Button(sShell, SWT.TOGGLE | SWT.CENTER);
			buttons[1].setBounds(146, 125, 78, 22);
			buttons[1].setBackgroundImage(bg);
			buttons[1].addMouseTrackListener(new MouseTrackAdapter() {
				public void mouseExit(MouseEvent evt) {
					label11.setText("");
				}
				public void mouseEnter(MouseEvent evt) {
					label11.setText(buttons[1].getToolTipText());
				}
			});
		}
		{
			buttons[2] = new Button(sShell, SWT.TOGGLE | SWT.CENTER);
			buttons[2].setBounds(224, 125, 78, 22);
			buttons[2].setBackgroundImage(bg);
			buttons[2].addMouseTrackListener(new MouseTrackAdapter() {
				public void mouseExit(MouseEvent evt) {
					label11.setText("");
				}
				public void mouseEnter(MouseEvent evt) {
					label11.setText(buttons[2].getToolTipText());
				}
			});
		}
		{
			buttons[3] = new Button(sShell, SWT.TOGGLE | SWT.CENTER);
			buttons[3].setBounds(302, 125, 78, 22);
			buttons[3].setBackgroundImage(bg);
			buttons[3].addMouseTrackListener(new MouseTrackAdapter() {
				public void mouseExit(MouseEvent evt) {
					label11.setText("");
				}
				public void mouseEnter(MouseEvent evt) {
					label11.setText(buttons[3].getToolTipText());
				}
			});
		}
		{
			buttons[4] = new Button(sShell, SWT.TOGGLE | SWT.CENTER);
			buttons[4].setBounds(380, 125, 78, 22);
			buttons[4].setBackgroundImage(bg);
			buttons[4].addMouseTrackListener(new MouseTrackAdapter() {
				public void mouseExit(MouseEvent evt) {
					label11.setText("");
				}
				public void mouseEnter(MouseEvent evt) {
					label11.setText(buttons[4].getToolTipText());
				}
			});
		}
		{
			itemListener = (new SelectionAdapter() {				
				public void widgetSelected(SelectionEvent evt) {
					//ToolItem currItem = (ToolItem) evt.widget;
					Button currItem = (Button) evt.widget;

					for(int i=0;i<5;i++){
						buttons[i].setSelection(false);
						// save the index of the button that was selected
						if(buttons[i].equals(currItem))
							selectionIndex = i+scrollIndex;
					}
					currItem.setSelection(true);
			        String node[] = (String []) currItem.getData();
			        // if current path is empty, set its name to root
			        if(text1.getText().equals(""))
			        	text1.setText(node[0]);
			        else
			        // else, update relative path
			        	text2.setText(node[0]);
			        // EXCEPTION: IF ROOT IS BOTH IN RELATIVE PATH AND CURRENT PATH, REMOVE IT FROM RELATIVE PATH
			        if(!text1.getText().contains("/") && text1.getText().equals(text2.getText()))
			        	text2.setText("");
			        String nameVal = node[0];
			        // enter Name = Value to Name/Value field
			        if(!node[1].equals(""))
			        	nameVal += " = " + node[1];
			        text3.setText(nameVal);
			        
			        try {
			        	// if no node is selected in the current node list, remove the last backslash in the current path
			        	if(!nodeSelected)
			        		fixCurrPath();
			        	// update tables
						renderTables();
						nodeSelected = true;
					} catch (Exception e1) {
						System.out.println("Failed to render tables!");
						//quick fix
						String[] arr=text1.getText().split(divider);
						String path="";
						for(int i=0;i<(arr.length-1);i++){
							if(!(arr[i].equals("")))  
								path+=divider+arr[i];
							} 
						arr=text2.getText().split(divider);
						path+=divider+arr[0]; 
						text1.setText(path);  
						if(arr.length>2){ 
							path=arr[1];
							for(int i=2;i<(arr.length-1);i++){
								path+=divider+arr[2];   
								}
							text2.setText(path); 
							}
						if(arr.length==2){
							path=arr[1]; 
							text2.setText(path); 
							}
						else{   
							text2.setText(""); 
							}
						try {
							renderTables();
							} catch (Exception e) {e.printStackTrace();} 
					}
				}
	        });
			for(int i=0;i<5;i++){
				buttons[i].addSelectionListener(itemListener);
				buttons[i].setEnabled(false);
				
			}

		}
		{
			label7 = new Label(sShell, SWT.NONE);
			label7.setBounds(17, 57, 120, 19);
			label7.setForeground(SWTResourceManager.getColor(255, 0, 0));
			label7.setBackgroundImage(bg);
		}
		{
			button6 = new Button(sShell, SWT.PUSH | SWT.CENTER);
			button6.setText("View Errors");
			button6.setBounds(25, 72, 82, 22);
			button6.setVisible(false);
			button6.addSelectionListener(new SelectionAdapter() {
				public void widgetSelected(SelectionEvent evt) {
					try {
						button6WidgetSelected(evt);
					} catch (Exception e) {e.printStackTrace();}
				}
			});
		}
		{
			button7 = new Button(sShell, SWT.PUSH | SWT.CENTER);
			button7.setText("Set");
			button7.setEnabled(false);
			button7.setBackgroundImage(bg);
			button7.setBounds(481, 28, 38, 22);

		}
		{
			list3 = new List(sShell, SWT.V_SCROLL | SWT.BORDER);
			list3.setBounds(270, 216, 92, 207);
			list3.setEnabled(false);
			scroll3=list3.getVerticalBar();
			scroll3.addListener (SWT.Selection, new Listener () {
				public void handleEvent (Event event) {
					scroll4.setSelection(scroll3.getSelection());
					list4.setTopIndex(list3.getTopIndex());
				}
			});
			list3.addMouseTrackListener(new MouseTrackAdapter() {
				public void mouseExit(MouseEvent evt) {
					label11.setText("");
				}
			});
			list3.addMouseMoveListener(new MouseMoveListener() {
				public void mouseMove(MouseEvent evt) {
					int element;
					//compute at which element of the list mouse cursor is
					element=scroll3.getSelection()+evt.y/list3.getItemHeight();
					if(element>=list3.getItemCount()){
						label11.setText("");
					}
					else{
						label11.setText(list3.getItem(element));
					}
				}
			});
		}   
		{   
			list4 = new List(sShell, SWT.V_SCROLL | SWT.BORDER);
			list4.setSelection(new java.lang.String[]{""});
			list4.setBounds(370, 216, 144, 207);
			list4.setEnabled(false);
			scroll4=list4.getVerticalBar();
			scroll4.addListener (SWT.Selection, new Listener () {
				public void handleEvent (Event event) {
					scroll3.setSelection(scroll4.getSelection());
					list3.setTopIndex(list4.getTopIndex());
				}
			});
			list4.addMouseTrackListener(new MouseTrackAdapter() {
				public void mouseExit(MouseEvent evt) {
					label11.setText("");
				}
			});
			list4.addMouseMoveListener(new MouseMoveListener() {
				public void mouseMove(MouseEvent evt) {
					int element;
					//compute at which element of the list mouse cursor is
					element=scroll4.getSelection()+evt.y/list4.getItemHeight();
					if(element>=list4.getItemCount()){
						label11.setText("");
					}
					else{
						label11.setText(list4.getItem(element));
					}
				}
			});
		}   
		{    
			label8 = new Label(sShell, SWT.LEFT | SWT.WRAP);
			label8.setText("Attributes:");
			label8.setBounds(270, 188, 92, 21);
			label8.setBackgroundImage(bg);
			label8.setForeground(SWTResourceManager.getColor(255,255,255));
		}    
		{     
			label9 = new Label(sShell, SWT.LEFT | SWT.WRAP);
		    label9.setText("Values:");
		    label9.setBounds(370, 188, 101, 21);
		    label9.setBackgroundImage(bg);
		    label9.setForeground(SWTResourceManager.getColor(255,255,255));
		} 
		{
			label10 = new Label(sShell, SWT.CENTER);
			label10.setBounds(17, 2, 492, 20);
			label10.setForeground(SWTResourceManager.getColor(0, 255, 0));
			label10.setBackgroundImage(bg);
		}
		{
			label11 = new Label(sShell, SWT.LEFT | SWT.BORDER);
			label11.setBounds(0, 462, 536, 19);
		}
	}
	//Open XML
	private void button1WidgetSelected(SelectionEvent evt) throws Exception {
		FileDialog fd=new FileDialog(sShell, SWT.OPEN);
		// open file dialog for xml files
		fd.setFilterExtensions(new String[]{"*.xml"});
		xmlFile=fd.open();
		if(xmlFile!=null){
			File xmlf = new File(xmlFile);
			// check if file exists
			if(xmlf.exists()){
				// enable screen
				text1.setEnabled(true);
				text2.setEnabled(true);
				text3.setEnabled(true);
				button2.setEnabled(true);
				button5.setEnabled(true);
				button7.setEnabled(true);
				list1.setEnabled(true);
				list2.setEnabled(true);
				list3.setEnabled(true);
				list4.setEnabled(true); 
				//fix for the texts keeping stuff when opening new XML
				//clear the pathes
				text1.setText("");
				text2.setText("");
				text3.setText("");
				label7.setText("");
				label10.setText("");
				//clear the lists
				list1.removeAll();
				list2.removeAll();
				list3.removeAll();
				list4.removeAll();
				//clear the nodes list
				for(int i=0;i<5;i++){
					buttons[i].setText("");
					buttons[i].setEnabled(false);
				}
				// load xml file
				loadXML();
				label10.setText("XML File: " + xmlf.toString());
				label10.setToolTipText(xmlf.toString());
			}
		}
	}
	//Forward
	private void button5WidgetSelected(SelectionEvent evt) throws Exception {
		if(list1.getSelectionCount()!=0){
			String path=text2.getText();
			path+=divider+list1.getSelection()[0];
			text2.setText(path);
			String fullpath=text1.getText()+divider+path;
			Node cur=getResult(fullpath).item(0);
			String value=getAttribute(cur);
			if(value==null) 
				text3.setText(list1.getSelection()[0]);
			else{  
				text3.setText(list1.getSelection()[0]+" = "+value);
				} 
			renderTables();
		}
	}
	

	//Back
	private void button2WidgetSelected(SelectionEvent evt) throws Exception {
		if(text2.getText()!=""){
			String cur=text2.getText();
			//split the expression and get the last instance
			String[] list=cur.split(divider);
			String todel=list[list.length-1];
			//construct the new expression
			if((cur.length()-todel.length()-1)>=0){
				String newexpr=cur.substring(0, cur.length()-todel.length()-1);
				text2.setText(newexpr);
				text3.setText(newexpr.split(divider)[newexpr.split(divider).length-1]);
				renderTables();
			}
			else{
				text2.setText("");
				text3.setText(curRoot.getLocalName());
				//Render a new tables for current subroot
				renderTables();
			}
		}
	}
	
	//Right arrow
	private void button4WidgetSelected(SelectionEvent evt) throws Exception {
		// move right only if there are nodes that do not fit the screen
		int amount = currNodes.size();
		if(amount>5 && scrollIndex+5<amount){
			// save item's contents as Previous Node
			scrollIndex++;
			// move button nodes left by one position
			for(int i=0;i<4;i++){
				buttons[i].setText(buttons[i+1].getText());
				buttons[i].setData(buttons[i+1].getData());
				buttons[i].setSelection(false);
				buttons[i].setToolTipText(buttons[i].getText());
			}
			
			button3.setEnabled(true);
			// change right arrow button to disabled if no more nodes to the right 
			if(scrollIndex+5>=amount)
				button4.setEnabled(false);
			// add new node to last button				
			String node[] = getNextNode(((String[])buttons[3].getData())[0]);
			// check if there is value
			if(!node[1].equals(""))
				buttons[4].setText(node[0] + " = " + node[1]);
			// else, display the node name
			else
				buttons[4].setText(node[0]);
			buttons[4].setData(node);
			buttons[4].setSelection(false);
			buttons[4].setToolTipText(buttons[4].getText());
			// if selected node is in the scrolling range, update selection of node
			if(selectionIndex >= scrollIndex && selectionIndex <= scrollIndex+4)
				buttons[selectionIndex-scrollIndex].setSelection(true);
		}
	}
	
	//Left arrow
	private void button3WidgetSelected(SelectionEvent evt) throws Exception {
		// move left only if there are nodes that do not fit the screen
		int amount = currNodes.size();
		if(amount>5 && scrollIndex>0){
			// Save last button node as the Next Node
			// increment the scrollIndex (moved right)
			scrollIndex--;
			button4.setEnabled(true);
			// change left arrow button to disabled if no more nodes to the left
			if(scrollIndex==0)
				button3.setEnabled(false);
			// 	move button contents right
			for(int i=4;i>0;i--){
				buttons[i].setText(buttons[i-1].getText());
				buttons[i].setData(buttons[i-1].getData());
				buttons[i].setSelection(false);
				buttons[i].setToolTipText(buttons[i].getText());
			}
			// add new node to first button
			String node[] = getPrevNode(((String[])buttons[1].getData())[0]);
			// check if there is value
			if(!node[1].equals(""))
				buttons[0].setText(node[0] + " = " + node[1]);
			// else, display the node name
			else
				buttons[0].setText(node[0]);
			buttons[0].setData(node);
			buttons[0].setSelection(false);
			buttons[0].setToolTipText(buttons[0].getText());
			// if selected node is in the scrolling range, update selection of node
			if(selectionIndex >= scrollIndex && selectionIndex <= scrollIndex+4)
				buttons[selectionIndex-scrollIndex].setSelection(true);
		}
	}
	
	// Errors button
	private void button6WidgetSelected(SelectionEvent evt) throws Exception {
		JOptionPane.showMessageDialog(null,errors);	
	}

	// Focus lost on Current Path button
	private void text1FocusLost(FocusEvent evt) {
		Runnable errorFocus = new Runnable() {public void run() {text1.setFocus();}};
		if(text1.getText().equals("")){
			JOptionPane.showMessageDialog(null,"Current Path cannot be empty!");
		    Display.getCurrent().asyncExec(errorFocus);
		}
		else if(!text1.getText().equals(prevPath)){		
			try {
				text2.setText("");
				text3.setText("");
				// no nodes selected
				nodeSelected = false;
				renderNodeList();
			} catch (Exception e) {
				JOptionPane.showMessageDialog(null,"Illegal XML Path. Try again!");
				// Get focus to text
				Display.getCurrent().asyncExec(errorFocus);
			}	
		}
	}
	
	private void text1FocusGained(FocusEvent evt) {
		prevPath = text1.getText();
	}
	
	
	/*
	 *
	 *    XPATH FUNCTIONS
	 *
	 */
	
	
	private void loadXML() throws Exception{
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		factory.setNamespaceAware(true);
		factory.setValidating(true);
		DocumentBuilder builder;
		builder = factory.newDocumentBuilder();
		builder.setErrorHandler(new org.xml.sax.ErrorHandler() {
			//To handle Fatal Errors
			public void fatalError(SAXParseException exception)throws SAXException {
				if(dtd.equals(""))
		        	label7.setText("XML file is invalid!");
				else
		        	label7.setText("DTD file is invalid!");
				errors.concat("Line: " +exception.getLineNumber() + "\nFatal Error: "+exception.getMessage()+"\n");
			}
			//To handle Errors
			public void error(SAXParseException e)throws SAXParseException {
				errors.concat("Line: " +e.getLineNumber() + "\nError: "+e.getMessage()+"\n");
			}
			//To Handle warnings
			public void warning(SAXParseException err)throws SAXParseException{
				errors.concat("Line: " +err.getLineNumber() + "\nWarning: "+err.getMessage()+"\n");
			}
			});
		doc = builder.parse(xmlFile);
        DocumentType docType = doc.getDoctype();
        if(docType==null)
        	label7.setText("No Doctype declared");
        else {
        	dtd =  docType.getSystemId();
	        // if XML has no DTD
	        if(dtd==null){
	        	label7.setText("XML file has no DTD");
	        }
	        // validate DTD
	        else {
		        File file = new File(xmlFile);
		        if(!file.exists())
		        	label7.setText("DTD file not found");
		        else
		        {
			        dtd = file.getAbsolutePath() + java.io.File.separator + dtd;
			        DOMSource source = new DOMSource(doc);        
			        StreamResult result = new StreamResult(System.out);
			        TransformerFactory tf = TransformerFactory.newInstance();
			        Transformer transformer = tf.newTransformer();
			        transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, dtd);
			        transformer.transform(source, result);
		        }
	        }
        }
		// load XML

		XPathFactory xf = XPathFactory.newInstance();
		XPath xpath = xf.newXPath();
		
		// get root
		XPathExpression expr = xpath.compile("node()");
		NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);

		// set Root node
		curRoot = (Element) nodes.item(0);
		String root = curRoot.getLocalName();
		String node[] = { root, "" };
		// set first button to be the root node
		buttons[0].setText(root);
		buttons[0].setData(node);
		buttons[0].setEnabled(true);
		buttons[0].setToolTipText(root);
		currNodes.put(node[0],node[1]);
		buttons[0].notifyListeners(SWT.Selection, new Event());
	}

	// retrieves the next node in the hash map
	private String[] getNextNode(String nodeName){
		Iterator<Entry<String,String>> iter = currNodes.entrySet().iterator();		
		Entry<String,String> entry;
		String[] node = { "", "" };
		// find the given node
		while(iter.hasNext() && !iter.next().getKey().equals(nodeName)){}
		// save next node
		if(iter.hasNext()){
			entry = iter.next();
			node[0] = entry.getKey();
			node[1] = entry.getValue();
		}
		// return next node
		return node;
			
	}
	// return the previous node in the Current Nodes hash
	private String[] getPrevNode(String nodeName){
		Iterator<Entry<String,String>> iter = currNodes.entrySet().iterator();		
		Entry<String,String> entry1=null, entry2 = null;
		String[] node = { "", "" };
		if(iter.hasNext()){
			entry1 = iter.next();
		}
		// search for the node
		while(iter.hasNext() && entry1!=null && !entry1.getKey().equals(nodeName)){
			// save previous node
			entry2 = entry1;
			entry1 = iter.next();
		}
		// return previous node
		node[0] = entry2.getKey();
		node[1] = entry2.getValue();
		return node;
	}
	
	// fills the toolbar with retrieved items
	// returns the amount of added items to the toolbar
	private int renderNodeButtons(){
		Entry<String,String> entry;
	// maximum 8 items in the toolbar
		int i=0;
		String name, value;
		for(i=0;i<5;i++){
			buttons[i].setSelection(false);
		}
		// amount of nodes that were found
		int nodes = currNodes.size();
		i = 0;
		// check if needs to enable the right arrow (more nodes than fit on the screen)
		if(nodes>5){
			button4.setEnabled(true);
		}
		// get minimum amount of nodes to be added to node buttons
		int size = Math.min(nodes,5);
		if(size>0){
			// add up to 5 nodes to node buttons
			Iterator<Entry<String,String>> iter = currNodes.entrySet().iterator();
			while(iter.hasNext() && i<size){
				entry = iter.next();
				name = entry.getKey();
				value = entry.getValue();
				
		        String node[] = { name, value };
				if(!value.equals(""))
					buttons[i].setText(name + " = " + value);
				// else, display the node name
				else
					buttons[i].setText(name);
		        // set item Data text
		        buttons[i].setData(node);
		        buttons[i].setEnabled(true);
				buttons[i].setToolTipText(buttons[i].getText());
		        //items.add(item);
				i++;
			}

		}
		// empty the rest of the buttons
		while(i<5){
			buttons[i].setText("");
			buttons[i].setToolTipText("");
			buttons[i].setData(null);
			buttons[i].setEnabled(false);
			i++;
		}
		return size;
	}	
	/*
	 * receives a relative path from the root and compiles the path returning a list of nodes as a result
	 */
	private NodeList getResult(String relativePath) throws Exception
	{
		//create an XPath factory
		XPathFactory factory = XPathFactory.newInstance();
		//create an XPath Object
		XPath xpath = factory.newXPath();
		//make the XPath object compile the XPath expression
		XPathExpression expr = xpath.compile(relativePath);
		return (NodeList) expr.evaluate(doc, XPathConstants.NODESET);		
		
	}
	
	// receives a list of nodes and builds a hash map of node attributes
	private HashMap<String,Integer> nodesToHashMap(NodeList nodes)
	{
		HashMap<String, Integer> hMap=new HashMap<String, Integer>();
		//populate the hash and identify the double instances
		for(int i=0;i<nodes.getLength();i++){
			if(nodes.item(i).getLocalName()!=null){
				String name=nodes.item(i).getNodeName();
				if(hMap.get(name)==null){
					Integer instance=new Integer(0);
					hMap.put(name, instance);
				}
				else{
					Integer val=hMap.get(name);
					if(val==0){
						val=1;
						hMap.remove(name);
						hMap.put(name, val);
					}
				}
			}
		}	
		return hMap;
	}
	
	// fill the toolbar of currentPath's direct children (Current node list)
	private void renderNodeList() throws Exception{
		NodeList nodes;
		// make sure that there is a relative path
		String path = text1.getText();
		if(path.trim().equals(""))
			path = "node()";
		nodes = getResult(path);
		String name, value;
		// illegal path
		if(nodes.getLength()==0)
			JOptionPane.showMessageDialog(null,"Illegal XML Path. Try again!");		
		else{		
			currNodes.clear();
			// get a map of all nodes and values
			TreeMap<String,String> nodesHash = getNodeAttrHash(nodes);
			for (Map.Entry<String,String> entry : nodesHash.entrySet()) {
				// put all nodes and values into a treemap
				name = entry.getKey();
				value = entry.getValue();
				currNodes.put(name,value);
			}
	
			// no nodes found, write value inside Name / Text
			if(renderNodeButtons()==0)
				text3.setText(nodes.item(0).getNodeValue());
		    list1.removeAll();
		    list2.removeAll();
		}
	}
	
	// get a hash map of Node names with enumeration and its attributes if exist
	private TreeMap<String,String> getNodeAttrHash(NodeList nodes){
		// get hash map of node names and counter of its appearances
		TreeMap<String,String> nodesHash = new TreeMap<String,String>();
		HashMap<String, Integer> hMap = nodesToHashMap(nodes);
		String nodeName, attr;
		// populate lists of attributes and nodes
		for (int i = 0; i < nodes.getLength(); i++) {
			// some XMLs contain illegal nodes which are carriage return chars \n\t they should be ignored
			if(nodes.item(i).getLocalName()!=null){
				String name=nodes.item(i).getLocalName();
				if(name!=null){
					Integer val=hMap.get(name);
					if(val==0){//only one with this name
						nodeName = name;
					}
					else{//several with this name
						nodeName = name+"["+val+"]";
						val++;
						hMap.remove(name);
						hMap.put(name, val);
					}
					String value = getAttribute(nodes.item(i));
					if(value!=null)
						attr = value;
					else
						attr = "";
					nodesHash.put(nodeName, attr);
				}
			}
		}
		return nodesHash;
	}
	
	// remove last value in the current path so that with relative path it would be a legal XPATH string
	private void fixCurrPath(){
		String path = text1.getText();
		int index = path.lastIndexOf("/");
		if(index>=0)
			text1.setText(path.substring(0,path.lastIndexOf("/")));
	}
	
	private void renderTables() throws Exception{
		/*
		 * fills the element and attribute tables according to relative path	
		 */
			NamedNodeMap nnm=null;
			NodeList nodes;
			list1.removeAll();
			list2.removeAll();
			list3.removeAll();   
			list4.removeAll(); 
			if(!text1.getText().equals("") || !text2.getText().equals("")){//need to consider the relative path
				String path;
				if(text2.getText().equals(""))
					path = text1.getText();
				else
				    path = text1.getText()+ "/" + text2.getText();
				nodes = getResult(path+"/node()");
				nnm=renderNNM(path+"/node()");
			}
			else{
				nodes = curRoot.getChildNodes();
				nnm=curRoot.getAttributes();
			}
			TreeMap<String,String> nodesHash = getNodeAttrHash(nodes);
			for (Map.Entry<String,String> entry : nodesHash.entrySet()) { 
			    list1.add(entry.getKey());
			    list2.add(entry.getValue());
			} 
			//populating attributes
			for(int i=0;i<nnm.getLength();i++){  
				list3.add(nnm.item(i).getLocalName()); 
				if(nnm.item(i).getNodeValue()!=null) 
					list4.add(nnm.item(i).getNodeValue());  
				else      
					list4.add(""); 
			}     
		}  
	/* 
	 * Returns map of attributes of the node at given path 
	 */      
	private NamedNodeMap renderNNM(String path) throws Exception {   
		NodeList list=getResult(path);   
		return list.item(0).getParentNode().getAttributes();  
	} 

	// get a node and return its attribute, if it has any
	private String getAttribute(Node node){
		// if node is attribute, display CDATA
		NodeList children = node.getChildNodes();
		if(children.getLength()==1){
			Node child = children.item(0);
			if(child.getNodeType() == Node.TEXT_NODE)
				return(child.getNodeValue());
		}
		return null;
	}
}